package testtiles;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

public class Define extends Properties {

	private static final long serialVersionUID = 1L;

	private File file;
	
	private ArrayList<Object> keys = new ArrayList<Object>();
	
	private List<String> imageAlias = new ArrayList<String>();
	private List<String> spriteAlias = new ArrayList<String>();
	private List<String> animationAlias = new ArrayList<String>();
	private List<String> unitClassAlias = new ArrayList<String>();
	private List<String> tilesetAlias = new ArrayList<String>();
	
	public Define(String path) {
		if (path == null) {
			throw new IllegalArgumentException("Argument 'path' is null ");
		}
		file = new File(path);
	}
	
	@Override
	public synchronized void clear() {
		imageAlias.clear();
		spriteAlias.clear();
		animationAlias.clear();
		unitClassAlias.clear();
		tilesetAlias.clear();
		keys.clear();
		super.clear();
	}

	@Override
	public synchronized Object put(Object key, Object value) {
		if (key != null && keys.contains(key) == false) {
			keys.add(key);
		}
		return super.put(key, value);
	}

	public void load() {
		InputStream istream = null;
		try {
			istream = new FileInputStream(file);
			load(istream);
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			try {
				if (istream != null) {
					istream.close();
				}
			} catch (IOException e) {
				// ignored
			}
		}
		prepareAlias();
	}

	@Override
	public synchronized Enumeration<Object> keys() {
		return Collections.enumeration(keys);
	}
	
	
	private void prepareAlias() {
		for (Object obj: keys) {
			String name = (String) obj;
			if (name.startsWith("image.")) {
				imageAlias.add(name);
			} else if (name.startsWith("sprite.")) {
				spriteAlias.add(name);
			} else if (name.startsWith("tileset")) {
				tilesetAlias.add(name);
			} else if (name.startsWith("animation.")) {
				animationAlias.add(name);
			} else if (name.startsWith("unitClass.")) {
				int pos = name.indexOf('.', 10);
				String namespace = name.substring(0, pos);
				if (unitClassAlias.contains(namespace) == false) {
					unitClassAlias.add(namespace);
				}
			}
		}
	}

	public List<String> getImageAlias() {
		return imageAlias;
	}

	public List<String> getSpriteAlias() {
		return spriteAlias;
	}

	public List<String> getAnimationAlias() {
		return animationAlias;
	}

	public List<String> getUnitClassAlias() {
		return unitClassAlias;
	}

	public List<String> getTilesetAlias() {
		return tilesetAlias;
	}
	
	public List<String> findKeys(String namespace) {
		if (namespace == null) {
			throw new IllegalArgumentException("Argument 'namespace' is null");
		}
//		String[] arr = namespace.split("\\.", 2);
//		String alias = arr[0];
//		List<String> list = null;
//		if (alias.startsWith("image")) {
//			list = imageAlias;
//		} else if (alias.startsWith("sprite")) {
//			list = spriteAlias;
//		} else if (alias.startsWith("animation")) {
//			list = animationAlias;
//		} else if (alias.startsWith("unitClass")) {
//			list = unitClassAlias;
//		}
//		if (list == null) {
//			throw new IllegalArgumentException("Alias not found: " + alias);
//		}
		ArrayList<String> found = new ArrayList<String>();
		for (Object obj: keys) {
			String name = obj.toString();
			if (name.startsWith(namespace)) {
				found.add(name);
			}
		}
		return found;
	}

	@SuppressWarnings("unchecked")
	public <T> T getValue(String key, Class<T> cls) {
		String value = getProperty(key);
		if (cls == Byte.class || cls == Byte.TYPE) {
			return (T)Byte.valueOf(value);
		}
		if (cls == Short.class || cls == Short.TYPE) {
			return (T)Short.valueOf(value);
		}
		if (cls == Integer.class || cls == Integer.TYPE) {
			return (T)Integer.valueOf(value);
		}
		if (cls == Long.class || cls == Long.TYPE) {
			return (T)Long.valueOf(value);
		}
		if (cls == Float.class || cls == Float.TYPE) {
			return (T)Float.valueOf(value);
		}
		if (cls == Double.class || cls == Double.TYPE) {
			return (T)Double.valueOf(value);
		}
		if (cls == Boolean.class || cls == Boolean.TYPE) {
			return (T)Boolean.valueOf(value);
		}
		return (T)value;
	}
		
}
